package cn.wolfcode.web.controller;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.utils.AssertUtil;
import cn.wolfcode.common.web.CodeMsg;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.config.AlipayProperties;
import cn.wolfcode.domain.PayResult;
import cn.wolfcode.domain.PayVo;
import cn.wolfcode.domain.RefundVo;
import cn.wolfcode.feign.SeckillFeignApi;
import cn.wolfcode.web.msg.PayCodeMsg;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/alipay")
public class AlipayController {
    private final AlipayClient alipayClient;
    private final AlipayProperties alipayProperties;
    private final SeckillFeignApi seckillFeignApi;

    public AlipayController(AlipayClient alipayClient, AlipayProperties alipayProperties, SeckillFeignApi seckillFeignApi) {
        this.alipayClient = alipayClient;
        this.alipayProperties = alipayProperties;
        this.seckillFeignApi = seckillFeignApi;
    }

    //发起支付宝支付
    @PostMapping("/prepay")
    public Result<String> prepay(@RequestBody PayVo payVo) {
        //1.封装请求支付信息
        JSONObject bizContent = new JSONObject();
        // 商户订单号，商户网站订单系统中唯一订单号，必填
        bizContent.put("out_trade_no", payVo.getOutTradeNo());
        // 订单名称，必填
        bizContent.put("subject", payVo.getSubject());
        // 付款金额，必填
        bizContent.put("total_amount", payVo.getTotalAmount());
        // 商品描述，可空
        bizContent.put("body", payVo.getBody());
        // 电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
        //设置未支付超时时间
        bizContent.put("time_expire",payVo.getTimeExpire());

        //2.设置相关信息
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        //设置请求支付信息
        alipayRequest.setBizContent(bizContent.toJSONString());
        //设置同步跳转地址，仅支持http/https
        alipayRequest.setReturnUrl(alipayProperties.getReturnUrl());
        //设置异步接受地址，仅支持http/https，公网可访问
        alipayRequest.setNotifyUrl(alipayProperties.getNotifyUrl());
        try {
            //3.发起支付
            AlipayTradePagePayResponse response = alipayClient.pageExecute(alipayRequest, "POST");
            if (response.isSuccess()) {
                //返回字符串form表单，然后支付宝调用该form提交表单，然后跳转到支付宝支付页面
                String form = response.getBody();
                log.info("[支付宝支付] 发起支付成功，收到支付响应结果：\n {}", form);
                return Result.success(form);
            }
            return Result.error(new CodeMsg(506001, response.getMsg()));
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return Result.error(PayCodeMsg.PAY_FAILED);
    }

    //同步回调
    @GetMapping("/return_url")
    public void payReturnUrl(@RequestParam Map<String, String> params, HttpServletResponse response) {
        log.info("[支付宝支付] 同步回调被调用了:{}", JSON.toJSONString(params));
        //验证同步回调参数签名
        try {
            boolean signVerified = AlipaySignature.rsaCheckV1(
                    params,
                    alipayProperties.getAlipayPublicKey(),
                    alipayProperties.getCharset(),
                    alipayProperties.getSignType()
            );
            AssertUtil.isTrue(signVerified, "同步回调签名验证失败");
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        try {
            //根据订单号，让用户重定向到订单详情页
            String orderDetailUrl = alipayProperties.getOrderDetailUrl() + "?orderNo=" + params.get("out_trade_no");
            response.sendRedirect(orderDetailUrl);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException(new CodeMsg(403, "重定向异常"));
        }
    }

    //异步回调
    @PostMapping("/notify_url")
    public String payNotifyUrl(@RequestParam Map<String, String> params) {
        log.info("[支付宝支付] 异步回调被调用了：{}", JSON.toJSONString(params));
        try {
            //验证异步回调参数签名
            boolean signVerified = AlipaySignature.rsaCheckV1(
                    params,
                    alipayProperties.getAlipayPublicKey(),
                    alipayProperties.getCharset(),
                    alipayProperties.getSignType()
            );
            AssertUtil.isTrue(signVerified, "支付宝异步回调签名验证失败");

            //订单状态
            String tradeStatus = params.get("trade_status");
            //订单编号
            String outTradeNo = params.get("out_trade_no");
            //支付流水号
            String tradeNo = params.get("trade_no");
            //支付金额
            String totalAmount = params.get("total_amount");

            // 获取订单支付状态
            if ("TRADE_SUCCESS".equals(tradeStatus)) {
                log.info("[支付宝异步回调] {} 订单已经支付成功", outTradeNo);
                //支付成功：更新订单的支付状态,支付类型,支付时间,并记录交易日志到MySQL中
                //远程调用进行更新
                PayResult payResult = new PayResult(outTradeNo, tradeNo, totalAmount);
                Result<?> result = seckillFeignApi.changeOrderStateAndPayLog(payResult);
                AssertUtil.isFalse(result.hasError(), "更新订单支付成功的状态失败");
            }
            return "success";
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return "fail";
    }


    //发起支付宝退款
    @PostMapping("/refund")
    public Result<Boolean> refund(@RequestBody RefundVo refundVo) {
        log.info("[支付宝退款] 准备发起退款操作 {}", JSON.toJSONString(refundVo));
        //1.退款请求对象
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        //2.封装请求退款信息
        JSONObject bizContent = new JSONObject();
        //支付宝交易号
        bizContent.put("out_trade_no", refundVo.getOutTradeNo());
        //退款金额
        bizContent.put("refund_amount", refundVo.getRefundAmount());
        //退款原因
        bizContent.put("refund_reason", refundVo.getRefundReason());
        //设置退款信息
        request.setBizContent(bizContent.toString());
        AlipayTradeRefundResponse response = null;
        try {
            //4.执行退款操作
            response = alipayClient.execute(request);
            log.info("[支付宝退款] 收到支付宝退款响应信息:{}", JSON.toJSONString(response));
            AssertUtil.isTrue(response.isSuccess(), response.getSubMsg());
            //退款成功
            if ("Y".equalsIgnoreCase(response.getFundChange())) {
                log.info("[支付宝退款] 退款成功");
                return Result.success(true);
            }
        } catch (AlipayApiException e) {
            log.warn("[支付宝退款] 退款失败 {}", e.getMessage());
            return Result.error(new CodeMsg(506001, e.getMessage()));
        }
        return Result.error(PayCodeMsg.REFUND_FAILED);
    }
}
